#pragma once
#include <expected>
#include "fastrpc/net.hpp"
#include "fastrpc/rpc/coder/fastpb_codec.hpp"
#include "fastrpc/rpc/common/rpc_util.hpp"
namespace fastrpc::rpc {
using namespace fastrpc::async;
using namespace fastrpc::net;
using namespace fastrpc::log;
using namespace fastrpc::rpc::util;

// 定义 RpcCoder concept
template <typename Coder, typename Protocol>
concept RpcCoder = requires(Coder coder, Protocol protocol, std::span<char> buf) {
    { coder.encode(protocol) } -> std::same_as<std::string>;
    { coder.decode(buf) } -> std::same_as<RpcResult<Protocol>>;
};

template <class Coder = detail::FastRpcCodec, class Protocol = FastPBProtocol>
    requires RpcCoder<Coder, Protocol>
class RpcFramed {
public:
    explicit RpcFramed(TcpStream &stream) : stream_{stream} {}

public:
    auto read_frame(std::span<char> buf) -> Task<RpcResult<Protocol>> {
        std::size_t nbytes = 0;
        while (true) {
            auto s = buf.subspan(nbytes, buf.size() - nbytes);
            auto read_result = co_await stream_.read(buf);
            if (!read_result) {
                console.error("{}", read_result.error().message());
                co_return std::unexpected{make_rpc_error(RpcError::ReadFailed)};
            }
            if (read_result.value() == 0) {
                co_return std::unexpected{make_rpc_error(RpcError::ReadEOF)};
            }
            nbytes += read_result.value();
            // 解码数据
            auto readed = buf.subspan(0, nbytes);
            auto decode_result = codec_.decode(readed);
            // console.info("decoded data size is:{}; pb_data size is:{}",
            //              decode_result.value().m_pk_len,
            //             decode_result.value().m_pb_data.length());
            if (!decode_result) {
                if (decode_result.error().value() == RpcError::InsufficientData) {
                    continue;
                } else {
                    console.error("{}", decode_result.error().message());
                    break;
                }
            }
            co_return decode_result;
        }
    }

    auto write_frame(Protocol &message) -> Task<RpcResult<bool>> {
        auto encoded = codec_.encode(message);
        // console.info("encoded data is:{}", encoded);
        auto write_result = co_await stream_.write(encoded);
        if (!write_result) {
            console.error("{}", write_result.error().message());
            co_return std::unexpected{make_rpc_error(RpcError::WriteFailed)};
        }
        co_return true;
    }

private:
    Coder      codec_;
    TcpStream &stream_;
};

}  // namespace fastrpc::rpc
